Flood Area Segmentation CNN

Johann Sebastian Catalla, BSCS-II

Professor: Dean Rodrigo Belleza Jr.
As partial fulfillment for the course CSAL101: Algorithms and Complexity

About The Dataset¶

The dataset is sourced from kaggle. It includes various images flood images. The folder is composed of the actual images and the masks which represents the flood area.

InĀ [7]:
# run once
#!pip install imantics --quiet
InĀ [8]:
import os
import cv2
import json
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import imantics
from PIL import Image
from skimage.transform import resize
from sklearn.model_selection import train_test_split
%matplotlib inline

Data Exploration and Preparation

The flood directory has two subdirectories: "Image" and "Mask". These subdirectories will hold the flood images and their associated masks that represent the flooded area.

InĀ [9]:
base_dir = 'flood'
images_dir = f'{base_dir}/Image'
masks_dir = f'{base_dir}/Mask'
InĀ [10]:
images_listdir = os.listdir(images_dir)
random_images = np.random.choice(images_listdir, size = 9, replace = False)
print(images_listdir[0:3])
['3059.jpg', '1049.jpg', '1080.jpg']
InĀ [11]:
image_size=512
input_image_size=(512,512)
InĀ [12]:
def read_image(path):
    img = cv2.imread(path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img = cv2.resize(img, (image_size, image_size))
    return img

Input images¶

I printed the sample images and their respective masks.

InĀ [13]:
rows = 3
cols = 3
fig, ax = plt.subplots(rows, cols, figsize = (8,8))
for i, ax in enumerate(ax.flat):
    if i < len(random_images):
        img = read_image(f"{images_dir}/{random_images[i]}")
        #print(img.shape)
        ax.set_title(f"{random_images[i]}")
        ax.imshow(img)
        ax.axis('off')
No description has been provided for this image

Ground truth masks¶

InĀ [14]:
fig, ax = plt.subplots(rows, cols, figsize = (8,8))
for i, ax in enumerate(ax.flat):
    if i < len(random_images):
        file=random_images[i][0:-4]+'.png'
        img = read_image(f"{masks_dir}/{file}")
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        ax.set_title(f"{random_images[i]}")
        ax.imshow(img)
        ax.axis('off')
No description has been provided for this image

I prepared the batches of flood images and their masks for further processing. I created two empty arrays: one for images and another for boolean masks.

The code reads the first 51 images and corresponding masks, resizes them if necessary, and stacks them into growing arrays. If there are errors reading a file, the code skips it and moves on to the next one.

InĀ [15]:
MASKS=np.zeros((1,image_size, image_size, 1), dtype=bool)
IMAGES=np.zeros((1,image_size, image_size, 3),dtype=np.uint8)

for j,file in enumerate(images_listdir[0:51]): ##the smaller, the faster
    try:
        image = read_image(f"{images_dir}/{file}")
        image_ex = np.expand_dims(image, axis=0)
        IMAGES = np.vstack([IMAGES, image_ex])

        file2=file[0:-4]+'.png'
        mask = read_image(f"{masks_dir}/{file2}")
        mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
        mask = mask.reshape(512,512,1)
        mask_ex = np.expand_dims(mask, axis=0)
        MASKS = np.vstack([MASKS, mask_ex])
    except:
        print(file)
        continue
InĀ [16]:
images=np.array(IMAGES)[1:51]
masks=np.array(MASKS)[1:51]
print(images.shape,masks.shape)
(50, 512, 512, 3) (50, 512, 512, 1)

The flood image and mask data are then splitted into training and testing sets. I utilized scikit-learn's train_test_split function.

Due to the limited number of images, I allocated 20% of the data for testing and the remaining 80% for training.

InĀ [17]:
images_train, images_test, masks_train, masks_test = train_test_split(
    images, masks, test_size=0.2, random_state=42)

Just ensuring the images train and masks train have the same size

InĀ [18]:
print(len(images_train), len(masks_train))
40 40

U-Net¶

I defined the U-Net for flood image segmentation. I created:

  1. A conv_block that stacks two convolutional layers with intervening batch normalization and ReLU activation, designed to extract image features.
  2. An encoder_block that applies a conv_block followed by pooling to capture features, reduce image size, and create skip connections for preserving details.
  3. A decoder_block that upsamples features, combines them with corresponding skip connections, and applies a conv_block for further processing.
  4. The core Unet function builds the U-Net architecture. It takes the input image shape and builds an encoder part with several encoder_blocks to extract features and shrink the image size, while creating skip connections along the way. A bridge block with a conv_block is used at the lowest level. The decoder part uses multiple decoder_blocks to progressively increase the resolution of the features and combine them with skip connections for detailed recovery. Finally, a convolution with sigmoid activation is applied to create the flood segmentation mask.
InĀ [19]:
def conv_block(input, num_filters):
    conv = tf.keras.layers.Conv2D(num_filters, 3, padding="same")(input)
    conv = tf.keras.layers.BatchNormalization()(conv)
    conv = tf.keras.layers.Activation("relu")(conv)
    conv = tf.keras.layers.Conv2D(num_filters, 3, padding="same")(conv)
    conv = tf.keras.layers.BatchNormalization()(conv)
    conv = tf.keras.layers.Activation("relu")(conv)
    return conv

def encoder_block(input, num_filters):
    skip = conv_block(input, num_filters)
    pool = tf.keras.layers.MaxPool2D((2, 2))(skip)
    return skip, pool

def decoder_block(input, skip, num_filters):
    up_conv = tf.keras.layers.Conv2DTranspose(num_filters, (2, 2), strides=2, padding="same")(input)
    conv = tf.keras.layers.Concatenate()([up_conv, skip])
    conv = conv_block(conv, num_filters)
    return conv

def Unet(input_shape):
    inputs = tf.keras.layers.Input(input_shape)

    skip1, pool1 = encoder_block(inputs, 64)
    skip2, pool2 = encoder_block(pool1, 128)
    skip3, pool3 = encoder_block(pool2, 256)
    skip4, pool4 = encoder_block(pool3, 512)

    bridge = conv_block(pool4, 1024)

    decode1 = decoder_block(bridge, skip4, 512)
    decode2 = decoder_block(decode1, skip3, 256)
    decode3 = decoder_block(decode2, skip2, 128)
    decode4 = decoder_block(decode3, skip1, 64)

    outputs = tf.keras.layers.Conv2D(1, 1, padding="same", activation="sigmoid")(decode4)

    model = tf.keras.models.Model(inputs, outputs, name="U-Net")
    return model

unet_model = Unet((512,512,3))
unet_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
unet_model.summary()
Model: "U-Net"
__________________________________________________________________________________________________
 Layer (type)                Output Shape                 Param #   Connected to                  
==================================================================================================
 input_1 (InputLayer)        [(None, 512, 512, 3)]        0         []                            
                                                                                                  
 conv2d (Conv2D)             (None, 512, 512, 64)         1792      ['input_1[0][0]']             
                                                                                                  
 batch_normalization (Batch  (None, 512, 512, 64)         256       ['conv2d[0][0]']              
 Normalization)                                                                                   
                                                                                                  
 activation (Activation)     (None, 512, 512, 64)         0         ['batch_normalization[0][0]'] 
                                                                                                  
 conv2d_1 (Conv2D)           (None, 512, 512, 64)         36928     ['activation[0][0]']          
                                                                                                  
 batch_normalization_1 (Bat  (None, 512, 512, 64)         256       ['conv2d_1[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_1 (Activation)   (None, 512, 512, 64)         0         ['batch_normalization_1[0][0]'
                                                                    ]                             
                                                                                                  
 max_pooling2d (MaxPooling2  (None, 256, 256, 64)         0         ['activation_1[0][0]']        
 D)                                                                                               
                                                                                                  
 conv2d_2 (Conv2D)           (None, 256, 256, 128)        73856     ['max_pooling2d[0][0]']       
                                                                                                  
 batch_normalization_2 (Bat  (None, 256, 256, 128)        512       ['conv2d_2[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_2 (Activation)   (None, 256, 256, 128)        0         ['batch_normalization_2[0][0]'
                                                                    ]                             
                                                                                                  
 conv2d_3 (Conv2D)           (None, 256, 256, 128)        147584    ['activation_2[0][0]']        
                                                                                                  
 batch_normalization_3 (Bat  (None, 256, 256, 128)        512       ['conv2d_3[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_3 (Activation)   (None, 256, 256, 128)        0         ['batch_normalization_3[0][0]'
                                                                    ]                             
                                                                                                  
 max_pooling2d_1 (MaxPoolin  (None, 128, 128, 128)        0         ['activation_3[0][0]']        
 g2D)                                                                                             
                                                                                                  
 conv2d_4 (Conv2D)           (None, 128, 128, 256)        295168    ['max_pooling2d_1[0][0]']     
                                                                                                  
 batch_normalization_4 (Bat  (None, 128, 128, 256)        1024      ['conv2d_4[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_4 (Activation)   (None, 128, 128, 256)        0         ['batch_normalization_4[0][0]'
                                                                    ]                             
                                                                                                  
 conv2d_5 (Conv2D)           (None, 128, 128, 256)        590080    ['activation_4[0][0]']        
                                                                                                  
 batch_normalization_5 (Bat  (None, 128, 128, 256)        1024      ['conv2d_5[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_5 (Activation)   (None, 128, 128, 256)        0         ['batch_normalization_5[0][0]'
                                                                    ]                             
                                                                                                  
 max_pooling2d_2 (MaxPoolin  (None, 64, 64, 256)          0         ['activation_5[0][0]']        
 g2D)                                                                                             
                                                                                                  
 conv2d_6 (Conv2D)           (None, 64, 64, 512)          1180160   ['max_pooling2d_2[0][0]']     
                                                                                                  
 batch_normalization_6 (Bat  (None, 64, 64, 512)          2048      ['conv2d_6[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_6 (Activation)   (None, 64, 64, 512)          0         ['batch_normalization_6[0][0]'
                                                                    ]                             
                                                                                                  
 conv2d_7 (Conv2D)           (None, 64, 64, 512)          2359808   ['activation_6[0][0]']        
                                                                                                  
 batch_normalization_7 (Bat  (None, 64, 64, 512)          2048      ['conv2d_7[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_7 (Activation)   (None, 64, 64, 512)          0         ['batch_normalization_7[0][0]'
                                                                    ]                             
                                                                                                  
 max_pooling2d_3 (MaxPoolin  (None, 32, 32, 512)          0         ['activation_7[0][0]']        
 g2D)                                                                                             
                                                                                                  
 conv2d_8 (Conv2D)           (None, 32, 32, 1024)         4719616   ['max_pooling2d_3[0][0]']     
                                                                                                  
 batch_normalization_8 (Bat  (None, 32, 32, 1024)         4096      ['conv2d_8[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_8 (Activation)   (None, 32, 32, 1024)         0         ['batch_normalization_8[0][0]'
                                                                    ]                             
                                                                                                  
 conv2d_9 (Conv2D)           (None, 32, 32, 1024)         9438208   ['activation_8[0][0]']        
                                                                                                  
 batch_normalization_9 (Bat  (None, 32, 32, 1024)         4096      ['conv2d_9[0][0]']            
 chNormalization)                                                                                 
                                                                                                  
 activation_9 (Activation)   (None, 32, 32, 1024)         0         ['batch_normalization_9[0][0]'
                                                                    ]                             
                                                                                                  
 conv2d_transpose (Conv2DTr  (None, 64, 64, 512)          2097664   ['activation_9[0][0]']        
 anspose)                                                                                         
                                                                                                  
 concatenate (Concatenate)   (None, 64, 64, 1024)         0         ['conv2d_transpose[0][0]',    
                                                                     'activation_7[0][0]']        
                                                                                                  
 conv2d_10 (Conv2D)          (None, 64, 64, 512)          4719104   ['concatenate[0][0]']         
                                                                                                  
 batch_normalization_10 (Ba  (None, 64, 64, 512)          2048      ['conv2d_10[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_10 (Activation)  (None, 64, 64, 512)          0         ['batch_normalization_10[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_11 (Conv2D)          (None, 64, 64, 512)          2359808   ['activation_10[0][0]']       
                                                                                                  
 batch_normalization_11 (Ba  (None, 64, 64, 512)          2048      ['conv2d_11[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_11 (Activation)  (None, 64, 64, 512)          0         ['batch_normalization_11[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_transpose_1 (Conv2D  (None, 128, 128, 256)        524544    ['activation_11[0][0]']       
 Transpose)                                                                                       
                                                                                                  
 concatenate_1 (Concatenate  (None, 128, 128, 512)        0         ['conv2d_transpose_1[0][0]',  
 )                                                                   'activation_5[0][0]']        
                                                                                                  
 conv2d_12 (Conv2D)          (None, 128, 128, 256)        1179904   ['concatenate_1[0][0]']       
                                                                                                  
 batch_normalization_12 (Ba  (None, 128, 128, 256)        1024      ['conv2d_12[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_12 (Activation)  (None, 128, 128, 256)        0         ['batch_normalization_12[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_13 (Conv2D)          (None, 128, 128, 256)        590080    ['activation_12[0][0]']       
                                                                                                  
 batch_normalization_13 (Ba  (None, 128, 128, 256)        1024      ['conv2d_13[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_13 (Activation)  (None, 128, 128, 256)        0         ['batch_normalization_13[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_transpose_2 (Conv2D  (None, 256, 256, 128)        131200    ['activation_13[0][0]']       
 Transpose)                                                                                       
                                                                                                  
 concatenate_2 (Concatenate  (None, 256, 256, 256)        0         ['conv2d_transpose_2[0][0]',  
 )                                                                   'activation_3[0][0]']        
                                                                                                  
 conv2d_14 (Conv2D)          (None, 256, 256, 128)        295040    ['concatenate_2[0][0]']       
                                                                                                  
 batch_normalization_14 (Ba  (None, 256, 256, 128)        512       ['conv2d_14[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_14 (Activation)  (None, 256, 256, 128)        0         ['batch_normalization_14[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_15 (Conv2D)          (None, 256, 256, 128)        147584    ['activation_14[0][0]']       
                                                                                                  
 batch_normalization_15 (Ba  (None, 256, 256, 128)        512       ['conv2d_15[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_15 (Activation)  (None, 256, 256, 128)        0         ['batch_normalization_15[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_transpose_3 (Conv2D  (None, 512, 512, 64)         32832     ['activation_15[0][0]']       
 Transpose)                                                                                       
                                                                                                  
 concatenate_3 (Concatenate  (None, 512, 512, 128)        0         ['conv2d_transpose_3[0][0]',  
 )                                                                   'activation_1[0][0]']        
                                                                                                  
 conv2d_16 (Conv2D)          (None, 512, 512, 64)         73792     ['concatenate_3[0][0]']       
                                                                                                  
 batch_normalization_16 (Ba  (None, 512, 512, 64)         256       ['conv2d_16[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_16 (Activation)  (None, 512, 512, 64)         0         ['batch_normalization_16[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_17 (Conv2D)          (None, 512, 512, 64)         36928     ['activation_16[0][0]']       
                                                                                                  
 batch_normalization_17 (Ba  (None, 512, 512, 64)         256       ['conv2d_17[0][0]']           
 tchNormalization)                                                                                
                                                                                                  
 activation_17 (Activation)  (None, 512, 512, 64)         0         ['batch_normalization_17[0][0]
                                                                    ']                            
                                                                                                  
 conv2d_18 (Conv2D)          (None, 512, 512, 1)          65        ['activation_17[0][0]']       
                                                                                                  
==================================================================================================
Total params: 31055297 (118.47 MB)
Trainable params: 31043521 (118.42 MB)
Non-trainable params: 11776 (46.00 KB)
__________________________________________________________________________________________________

Train¶

I trained the U-Net flood segmentation model I built earlier. I fed the training flood images and their corresponding masks into the model's fit function.

To monitor the model's learning and prevent overfitting, I dedicated 20% of the training data for validation. I also trained the model in batches of 4 images and ran the training process for 40 epochs.

InĀ [20]:
unet_result = unet_model.fit(
    images_train, masks_train,
    validation_split = 0.2, batch_size = 4, epochs = 40)
Epoch 1/40
8/8 [==============================] - 69s 1s/step - loss: -317.5229 - accuracy: 0.3060 - val_loss: -224273.7188 - val_accuracy: 0.1993
Epoch 2/40
8/8 [==============================] - 9s 1s/step - loss: -531.4960 - accuracy: 0.3952 - val_loss: 24078060.0000 - val_accuracy: 0.6145
Epoch 3/40
8/8 [==============================] - 8s 1s/step - loss: -640.2673 - accuracy: 0.4209 - val_loss: 13830448.0000 - val_accuracy: 0.6145
Epoch 4/40
8/8 [==============================] - 8s 1s/step - loss: -657.3428 - accuracy: 0.3698 - val_loss: 26745482.0000 - val_accuracy: 0.6145
Epoch 5/40
8/8 [==============================] - 9s 1s/step - loss: -731.2119 - accuracy: 0.3232 - val_loss: 19639602.0000 - val_accuracy: 0.6145
Epoch 6/40
8/8 [==============================] - 8s 1s/step - loss: -777.8339 - accuracy: 0.2761 - val_loss: 6624048.0000 - val_accuracy: 0.6145
Epoch 7/40
8/8 [==============================] - 8s 1s/step - loss: -883.8488 - accuracy: 0.2718 - val_loss: 248768.1562 - val_accuracy: 0.6145
Epoch 8/40
8/8 [==============================] - 8s 1s/step - loss: -903.3406 - accuracy: 0.2562 - val_loss: 2772233.0000 - val_accuracy: 0.6145
Epoch 9/40
8/8 [==============================] - 8s 1s/step - loss: -981.9388 - accuracy: 0.2353 - val_loss: 1954045.3750 - val_accuracy: 0.6145
Epoch 10/40
8/8 [==============================] - 8s 1s/step - loss: -1091.8596 - accuracy: 0.2073 - val_loss: 283093.3750 - val_accuracy: 0.6145
Epoch 11/40
8/8 [==============================] - 8s 1s/step - loss: -1085.4352 - accuracy: 0.1956 - val_loss: 315885.9062 - val_accuracy: 0.6145
Epoch 12/40
8/8 [==============================] - 8s 1s/step - loss: -1198.9594 - accuracy: 0.1802 - val_loss: 236124.2812 - val_accuracy: 0.6145
Epoch 13/40
8/8 [==============================] - 8s 1s/step - loss: -1242.6714 - accuracy: 0.1597 - val_loss: 240205.2500 - val_accuracy: 0.6145
Epoch 14/40
8/8 [==============================] - 8s 1s/step - loss: -1300.0221 - accuracy: 0.1709 - val_loss: 3917.5037 - val_accuracy: 0.6145
Epoch 15/40
8/8 [==============================] - 8s 1s/step - loss: -1396.0645 - accuracy: 0.1562 - val_loss: 2392.7568 - val_accuracy: 0.6144
Epoch 16/40
8/8 [==============================] - 8s 1s/step - loss: -1467.0767 - accuracy: 0.1672 - val_loss: 1757.9507 - val_accuracy: 0.6145
Epoch 17/40
8/8 [==============================] - 8s 1s/step - loss: -1547.5094 - accuracy: 0.1540 - val_loss: 1732.1936 - val_accuracy: 0.6145
Epoch 18/40
8/8 [==============================] - 8s 1s/step - loss: -1613.5913 - accuracy: 0.1581 - val_loss: 3715.2363 - val_accuracy: 0.6145
Epoch 19/40
8/8 [==============================] - 9s 1s/step - loss: -1693.0769 - accuracy: 0.1835 - val_loss: 1269.3572 - val_accuracy: 0.6140
Epoch 20/40
8/8 [==============================] - 8s 1s/step - loss: -1781.1072 - accuracy: 0.1847 - val_loss: 1794.1149 - val_accuracy: 0.6142
Epoch 21/40
8/8 [==============================] - 9s 1s/step - loss: -1856.1777 - accuracy: 0.1681 - val_loss: 904.4265 - val_accuracy: 0.6027
Epoch 22/40
8/8 [==============================] - 9s 1s/step - loss: -1999.6028 - accuracy: 0.1650 - val_loss: 299.8980 - val_accuracy: 0.5474
Epoch 23/40
8/8 [==============================] - 8s 1s/step - loss: -2046.9307 - accuracy: 0.1603 - val_loss: 1699.7529 - val_accuracy: 0.5603
Epoch 24/40
8/8 [==============================] - 8s 1s/step - loss: -2173.3223 - accuracy: 0.1588 - val_loss: 6372.9893 - val_accuracy: 0.6128
Epoch 25/40
8/8 [==============================] - 8s 1s/step - loss: -2274.5242 - accuracy: 0.1782 - val_loss: 4972.4424 - val_accuracy: 0.6133
Epoch 26/40
8/8 [==============================] - 8s 1s/step - loss: -2344.7363 - accuracy: 0.1799 - val_loss: 1141.7584 - val_accuracy: 0.6005
Epoch 27/40
8/8 [==============================] - 9s 1s/step - loss: -2505.2192 - accuracy: 0.1787 - val_loss: 460.8345 - val_accuracy: 0.6080
Epoch 28/40
8/8 [==============================] - 8s 1s/step - loss: -2556.1479 - accuracy: 0.1993 - val_loss: 1334.6827 - val_accuracy: 0.6123
Epoch 29/40
8/8 [==============================] - 8s 1s/step - loss: -2741.0308 - accuracy: 0.1731 - val_loss: 36.2159 - val_accuracy: 0.6046
Epoch 30/40
8/8 [==============================] - 8s 1s/step - loss: -2761.2593 - accuracy: 0.1664 - val_loss: -937.1934 - val_accuracy: 0.1831
Epoch 31/40
8/8 [==============================] - 8s 1s/step - loss: -2859.8491 - accuracy: 0.1541 - val_loss: 34.2534 - val_accuracy: 0.4544
Epoch 32/40
8/8 [==============================] - 9s 1s/step - loss: -3016.6003 - accuracy: 0.1442 - val_loss: -101.6258 - val_accuracy: 0.2162
Epoch 33/40
8/8 [==============================] - 8s 1s/step - loss: -3206.3298 - accuracy: 0.1309 - val_loss: 824.6451 - val_accuracy: 0.5821
Epoch 34/40
8/8 [==============================] - 8s 1s/step - loss: -3226.0547 - accuracy: 0.1123 - val_loss: 862.4459 - val_accuracy: 0.5778
Epoch 35/40
8/8 [==============================] - 9s 1s/step - loss: -3415.1719 - accuracy: 0.1251 - val_loss: -1224.5474 - val_accuracy: 0.1952
Epoch 36/40
8/8 [==============================] - 8s 1s/step - loss: -3552.5605 - accuracy: 0.1531 - val_loss: 1542.0995 - val_accuracy: 0.5950
Epoch 37/40
8/8 [==============================] - 9s 1s/step - loss: -3715.8950 - accuracy: 0.1308 - val_loss: 197.9382 - val_accuracy: 0.6026
Epoch 38/40
8/8 [==============================] - 9s 1s/step - loss: -3834.2515 - accuracy: 0.1355 - val_loss: -118.9549 - val_accuracy: 0.5089
Epoch 39/40
8/8 [==============================] - 8s 1s/step - loss: -3955.6641 - accuracy: 0.1356 - val_loss: 2189.6885 - val_accuracy: 0.6086
Epoch 40/40
8/8 [==============================] - 9s 1s/step - loss: -4128.2051 - accuracy: 0.1345 - val_loss: -804.7332 - val_accuracy: 0.2587

Predict¶

InĀ [21]:
unet_predict = unet_model.predict(images_test)
1/1 [==============================] - 30s 30s/step

I created four sets of predictions from the U-Net model's output (unet_predict) on the test images. Here's what I did for each:

  1. unet_predict1: I used a threshold of 0.1. The code creates a new variable unet_predict1 by comparing each value in unet_predict to 0.1. If the value in unet_predict is greater than 0.1, it gets assigned a 1 (indicating likely flood pixels). Otherwise, it gets assigned a 0. Finally, I convert the resulting array to the uint8 data type.

  2. unet_predict2, unet_predict3, unet_predict4: I repeated the same process for unet_predict2, unet_predict3, and unet_predict4 but with different thresholds (0.2, 0.3, and 0.4 respectively). This essentially creates four potential flood segmentation masks with varying strictness. A higher threshold means only pixels with a higher probability of being flood will be included in the mask.

InĀ [22]:
unet_predict1 = (unet_predict > 0.1).astype(np.uint8)
unet_predict2 = (unet_predict > 0.2).astype(np.uint8)
unet_predict3 = (unet_predict > 0.3).astype(np.uint8)
unet_predict4 = (unet_predict > 0.4).astype(np.uint8)
InĀ [23]:
len(unet_predict)
Out[23]:
10

I defined a function called show_result to help me analyze the flood segmentation predictions from my U-Net model. This function lets me visually compare the original flood image, the model's prediction for that image, and the ground truth mask (the actual flood mask) all side-by-side.

The function creates a figure with three subplots.

In the first subplot, I display the original flood image with the title "Original."

In the second subplot, I display the prediction from my U-Net model for that image. I also include a title in this subplot that specifies the threshold value I used to create the prediction (e.g., "U-Net: p>0.2").

Finally, in the third subplot, I display the ground truth mask, which represents the actual flooded areas in the image. This subplot is titled "Ground Truth." By turning off the axis labels in each subplot, I create a clean visualization that allows me to focus on the image content.

InĀ [24]:
def show_result(og, unet, target, p):

    fig, axs = plt.subplots(1, 3, figsize=(12,12))
    axs[0].set_title("Original")
    axs[0].imshow(og)
    axs[0].axis('off')

    axs[1].set_title("U-Net: p>"+str(p))
    axs[1].imshow(unet)
    axs[1].axis('off')

    axs[2].set_title("Ground Truth")
    axs[2].imshow(target)
    axs[2].axis('off')

    plt.show()
InĀ [25]:
show_test_idx = random.sample(range(len(unet_predict)), 3)
for idx in show_test_idx:
    show_result(images_test[idx], unet_predict1[idx], masks_test[idx], 0.1)
    show_result(images_test[idx], unet_predict2[idx], masks_test[idx], 0.2)
    show_result(images_test[idx], unet_predict3[idx], masks_test[idx], 0.3)
    show_result(images_test[idx], unet_predict4[idx], masks_test[idx], 0.4)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

In the first subplot, I display the original flood image with the title "Original."

In the second subplot, I display the prediction from my U-Net model for that image. I also include a title in this subplot that specifies the threshold value I used to create the prediction (e.g., "U-Net: p>0.2").

Finally, in the third subplot, I display the ground truth mask, which represents the actual flooded areas in the image. This subplot is titled "Ground Truth." By turning off the axis labels in each subplot, I create a clean visualization that allows me to focus on the image content.

In these plots we can see the 4 thresholds as well as the input and output of the model, and ground truth. By observing these results, we can say that the higher threshold has a more accurate prediction of the flood area.

InĀ [25]: